using System.Collections;
using System.Text.RegularExpressions;

namespace NalogGarLoader.Model.GarRepositoryReader;

public abstract partial class GarRepositoryReader : IEnumerable<GarRepositoryEntry>
{
    [GeneratedRegex("gar_delta_xml")]
    private static partial Regex GarDeltaFileNameRegEx();
    [GeneratedRegex("gar_xml")]
    private static partial Regex GarFullFileNameRegEx();
        
    public DateOnly GarVersion { get; protected set; } 
    public bool? IsIncremental { get; private set; }

    protected string SourcePath { get; init; }
    protected HashSet<string> TableImportSet{ get; init; }

    public GarRepositoryReader(string sourcePath, HashSet<string> tableImportSet)
    {
        this.SourcePath = sourcePath;
        this.TableImportSet = tableImportSet;
        
        this.ReadGarVersion();        

        if (this.GarVersion == DateOnly.MinValue)
            throw new ArgumentException("Не удалось определить версию ГАР из репозитория");

        this.ReadRepoType();
    }

    private void ReadRepoType()
    {
        string sourceName = Path.GetFileNameWithoutExtension(this.SourcePath);

        Regex incRegEx = GarDeltaFileNameRegEx();
        Regex fullRegEx = GarFullFileNameRegEx();

        if (incRegEx.IsMatch(sourceName))
            this.IsIncremental = true;
        else if(fullRegEx.IsMatch(sourceName))
            this.IsIncremental = false;
        else
            this.IsIncremental = null;
    }

    protected abstract void ReadGarVersion();

    protected string? ParseGarType(string fileName)
    {
        if (string.IsNullOrWhiteSpace(fileName))
            throw new ArgumentNullException(nameof(fileName));

        string[] fileNameSplit = Path.GetFileNameWithoutExtension(fileName).Split('_');

        if (fileNameSplit.Length < 3)
            return null;

        return string.Join('_', fileNameSplit[0..^2]);
    }

    public abstract IEnumerator<GarRepositoryEntry> GetEnumerator();

    protected abstract Stream GetFileStream(GarRepositoryEntry garRepositoryEntry);   

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    public static GarRepositoryReader Open(string repositoryPath, HashSet<string> tableImportSet)
    {
        ArgumentNullException.ThrowIfNull(repositoryPath);
        ArgumentNullException.ThrowIfNull(tableImportSet);

        if (!File.Exists(repositoryPath) && !Directory.Exists(repositoryPath))
            throw new FileNotFoundException(repositoryPath);

        var attr = File.GetAttributes(repositoryPath);

        if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
        {
            return new GarDirectoryRepositoryReader(repositoryPath, tableImportSet);
        } 
        else if ((attr & FileAttributes.Archive) == FileAttributes.Archive)
        {
            return new GarZipFileRepositoryReader(repositoryPath, tableImportSet);
        }
                        
        throw new InvalidDataException($"Repository {repositoryPath} is not supporting");
    }
}